/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package stud.cp.user.dbaccess;

import java.math.BigInteger;
import java.sql.*;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import stud.cp.core.dbaccess.DAO;
import stud.cp.core.dbaccess.DAOException;
import stud.cp.user.valueobjects.DBObjectType;

/**
 * Класс доступа к таблице с типами оружия.
 *
 * @author Morfant
 */
public class ObjectTypesDAO implements DAO<DBObjectType> {

    /**
     * Логгер.
     */
    private static Logger logger = Logger.getLogger("ACPII");
    /**
     * Список названий колонок таблицы weapon_types.
     */
    private static String[] dbObjectTypesColumnName = {
        "object_type_id",
        "name",
        "description",
        "parent_id",
        "isAbstract",
        "isDelete"};
    /**
     * Коннект к базе данных.
     */
    private Connection connection = null;

    /**
     * Конструктор, который создает коннект к базе данных.
     */
    public ObjectTypesDAO(Connection connection) {
        this.connection = connection;
    }

    private String getQueryForObjectTypeHeirs(BigInteger objectTypeId) {
        StringBuilder query = new StringBuilder();
        query.append("select object_type_id,name,description,parent_id,isAbstract,isDelete \n");
        query.append("from object_types obj_type\n");
        query.append("where obj_type.parent_id = ");
        query.append(objectTypeId);
        return query.toString();
    }

    public List<DBObjectType> getObjectTypeHeirs(BigInteger objectTypeId) throws DAOException {
        List<DBObjectType> data_list = new LinkedList<DBObjectType>();
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            logger.debug("Query = " + getQueryForObjectTypeHeirs(objectTypeId));
            prestat = connection.prepareStatement(getQueryForObjectTypeHeirs(objectTypeId));
            set = prestat.executeQuery();
            while (set.next()) {
                data_list.add(new DBObjectType(set.getBigDecimal(dbObjectTypesColumnName[0]).toBigInteger(),
                        set.getString(dbObjectTypesColumnName[1]),
                        set.getString(dbObjectTypesColumnName[2]),
                        set.getBigDecimal(dbObjectTypesColumnName[3]) != null
                        ? set.getBigDecimal(dbObjectTypesColumnName[3]).toBigInteger() : null,
                        set.getBoolean(dbObjectTypesColumnName[4]),
                        set.getBoolean(dbObjectTypesColumnName[5])));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_weapon_type", ex);
            throw new DAOException("Ошибка получения списка данных", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
        return data_list;

    }

    /**
     * Запрос, позволяющий при выполнении получить полностью данные из таблицы
     * weapon_types.
     *
     * @return Строка запроса.
     */
    private String getQueryForAllWeaponType() {
        StringBuilder query = new StringBuilder();
        query.append("select object_type_id,name,description,parent_id,isAbstract,isDelete \n");
        query.append("from object_types");
        return query.toString();
    }

    /**
     * Метод, который возвращает список значений из таблицы weapon_types.
     *
     * @return Список данных.
     */
    @Override
    public List<DBObjectType> getAll() throws DAOException {
        List<DBObjectType> data_list = new LinkedList<DBObjectType>();
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            logger.debug("Query = " + getQueryForAllWeaponType());
            prestat = connection.prepareStatement(getQueryForAllWeaponType());
            set = prestat.executeQuery();
            while (set.next()) {
                data_list.add(new DBObjectType(set.getBigDecimal(dbObjectTypesColumnName[0]).toBigInteger(),
                        set.getString(dbObjectTypesColumnName[1]),
                        set.getString(dbObjectTypesColumnName[2]),
                        set.getBigDecimal(dbObjectTypesColumnName[3]) != null
                        ? set.getBigDecimal(dbObjectTypesColumnName[3]).toBigInteger() : null,
                        set.getBoolean(dbObjectTypesColumnName[4]),
                        set.getBoolean(dbObjectTypesColumnName[5])));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_weapon_type", ex);
            throw new DAOException("Ошибка получения списка данных", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
        return data_list;
    }

    /**
     * Запрос, позволяющий получить запись по id.
     *
     * @param id ID
     * @return Запрос.
     */
    private String getQueryForGetById(BigInteger id) {
        StringBuilder query = new StringBuilder();

        query.append("SELECT object_type_id, name,description,parent_id,isAbstract,isDelete \n");
        query.append("FROM object_types \n");
        query.append("WHERE object_type_id=");
        query.append(id);

        return query.toString();
    }

    /**
     * Метод, позволяющий получить запись по её ID
     *
     * @param id ID
     * @return Данные записи.
     * @throws DAOException <p> Ошикба доступа к данным. </p>
     */
    @Override
    public DBObjectType getById(BigInteger id) throws DAOException {
        DBObjectType weaponType = null;
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            logger.debug("Query = " + getQueryForGetById(id));
            prestat = connection.prepareStatement(getQueryForGetById(id));
            set = prestat.executeQuery();
            if (set.next()) {
                weaponType = new DBObjectType(set.getBigDecimal(dbObjectTypesColumnName[0]).toBigInteger(),
                        set.getString(dbObjectTypesColumnName[1]),
                        set.getString(dbObjectTypesColumnName[2]),
                        set.getBigDecimal(dbObjectTypesColumnName[3]) != null
                        ? set.getBigDecimal(dbObjectTypesColumnName[3]).toBigInteger() : null,
                        set.getBoolean(dbObjectTypesColumnName[4]),
                        set.getBoolean(dbObjectTypesColumnName[5]));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_propety", ex);
            throw new DAOException("Ошибка при создание данных..", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
        return weaponType;
    }

    /**
     * Запрос на обновление записи в таблице.
     *
     * @param id ID
     * @param name Имя
     * @return Запрос.
     */
    private String getQueryForUpdate(BigInteger id, String name, String description, Integer isDelete) {
        StringBuilder query = new StringBuilder();
        query.append("UPDATE object_types \n ");
        query.append("SET name='");
        query.append(name);
        query.append("', description='");
        query.append(description);
        query.append("',isDelete=");
        query.append(isDelete);
        query.append(" \n ");
        query.append("WHERE object_type_id=");
        query.append(id);
        return query.toString();
    }

    /**
     * Метод, отвечающий за обновление данных.
     *
     * @param entry Запись.
     * @throws DAOException Ошибка при обновление данных.
     */
    @Override
    public void update(DBObjectType entry) throws DAOException {
        PreparedStatement prestat = null;
        try {
            logger.debug("Query = " + getQueryForUpdate(
                    entry.getObject_type_id(),
                    entry.getName(),
                    entry.getDescription(),
                    entry.getIsTemporaryDelete() == true ? 1 : 0));
            prestat = connection.prepareStatement(
                    getQueryForUpdate(
                    entry.getObject_type_id(),
                    entry.getName(),
                    entry.getDescription(),
                    entry.getIsTemporaryDelete() == true ? 1 : 0));
            prestat.executeUpdate();
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка обновлени данных.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
    }

    /**
     * Зарпос на получения следующего ID.
     *
     * @return Зарпос.
     */
    private String getQueryForSelectNextID() {
        StringBuilder query = new StringBuilder();
        query.append("SELECT weapon_types_seq.NEXTVAL from dual \n");
        return query.toString();
    }

    /**
     * Зарпос на получения максимального id из таблицы.
     *
     * @return Зарпос.
     */
    private String getQueryForSelectMaxId() {
        StringBuilder query = new StringBuilder();
        query.append("SELECT MAX(weapon_type_id) \n");
        query.append("FROM weapon_types");
        return query.toString();
    }

    /**
     * Запрос на добавление новой записи в таблицу.
     *
     * @param id ID
     * @param name Имя
     * @param description Описание.
     * @return Запрос.
     */
    private String getQueryForInsert(BigInteger id, String name, String description, BigInteger parentId, Integer isAbstract, Integer isDelete) {
        StringBuilder query = new StringBuilder();
        query.append("INSERT INTO object_types(object_type_id,name,description,parent_id,isAbstract,isDelete) \n");
        query.append("VALUES(");
        query.append(id);
        query.append(",'");
        query.append(name);
        query.append("','");
        query.append(description);
        query.append("',");
        query.append(parentId);
        query.append(",");
        query.append(isAbstract);
        query.append(",");
        query.append(isDelete);
        query.append(")");
        return query.toString();
    }

    /**
     * Метод, который создает новую запись в таблице.
     *
     * @param entry Запись.
     * @throws DAOException Ошибка создания новой записи.
     */
    @Override
    public BigInteger create(DBObjectType entry) throws DAOException {
        ResultSet set = null;
        PreparedStatement prestat = null;
        CallableStatement proc;
        try {
            proc = connection.prepareCall("{ call GetNextIdentity(?,?)}");
            proc.setString(1, "object_property");
            proc.registerOutParameter(2, java.sql.Types.BIGINT);

            proc.execute();

            BigInteger index = proc.getBigDecimal(2).toBigInteger();

            proc.close();

            logger.debug("Query = " + getQueryForInsert(
                    index, entry.getName(),
                    entry.getDescription(),
                    entry.getParentId(),
                    entry.getIsAbstract() == true ? 1 : 0,0));
            prestat = connection.prepareStatement(getQueryForInsert(
                    index, entry.getName(),
                    entry.getDescription(),
                    entry.getParentId(),
                    entry.getIsAbstract() == true ? 1 : 0,0));
            prestat.executeUpdate();
            return index;
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка при создание записи.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
    }

    /**
     * Зарпос на удаление из таблицы записи по id.
     *
     * @param id ID
     * @return Зарпос.
     */
    private String getQueryForDelete(BigInteger id) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM object_types \n");
        query.append("WHERE object_type_id=");
        query.append(id);
        return query.toString();
    }

    /**
     * Запрос на все оружие относящееся к конкретному типу оружия.
     *
     * @param weapon_type_id ID типа оружия.
     * @return Запрос.
     */
    private String getQueryForObjects(BigInteger weapon_type_id) {
        StringBuilder query = new StringBuilder();
        query.append("select object_id \n");
        query.append("from objects \n");
        query.append("where object_type_id=");
        query.append(weapon_type_id);
        return query.toString();
    }

    /**
     * Запрос на все расширения типа относящееся к конкретному типу оружия.
     *
     * @param objectTypeId ID типа оружия.
     * @return Запрос.
     */
    private String getQueryForPropertyTypeDefsForObjectType(BigInteger objectTypeId) {
        StringBuilder query = new StringBuilder();
        query.append("select property_type_def_id \n");
        query.append("from property_type_defs \n");
        query.append("where object_type_id=");
        query.append(objectTypeId);
        return query.toString();
    }

    /**
     * Удаление из табилцы property_values.
     *
     * @param objectId ID оружия.
     * @return Зарпос.
     */
    private String getQueryForDeleteFromParameters(BigInteger objectId) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM parameters \n");
        query.append("WHERE object_id=");
        query.append(objectId);
        return query.toString();
    }

    /**
     * Удаление из табилцы weapon_references.
     *
     * @param objectId ID оружия.
     * @return Зарпос.
     */
    private String getQueryForDeleteFromObjectReferences(BigInteger objectId) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM object_references \n");
        query.append("WHERE object_id=");
        query.append(objectId);
        query.append("\n OR reference_object_id=");
        query.append(objectId);
        return query.toString();
    }

    /**
     * Удаление из табилцы weapon_types_properties.
     *
     * @param objectTypeId ID типа оружия.
     * @return Зарпос.
     */
    private String getQueryForDeleteFromObjectTypeProperties(BigInteger objectTypeId) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM object_type_properties \n");
        query.append("WHERE object_type_id=");
        query.append(objectTypeId);
        return query.toString();
    }

    /**
     * Удаление из табилцы weapons.
     *
     * @param objectTypeId ID типа оружия.
     * @return Зарпос.
     */
    private String getQueryForDeleteFromObjects(BigInteger objectTypeId) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM objects \n");
        query.append("WHERE object_type_id=");
        query.append(objectTypeId);
        return query.toString();
    }

    /**
     * Операция удаления записи из таблицы.
     *
     * @param id Объект, который надо удалить.
     */
    @Override
    public void delete(BigInteger id) throws DAOException {
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            logger.debug("Query = " + getQueryForObjects(id));
            prestat = connection.prepareStatement(getQueryForObjects(id));
            set = prestat.executeQuery();
            List<BigInteger> data_list = new LinkedList<BigInteger>();
            while (set.next()) {
                data_list.add(set.getBigDecimal(1).toBigInteger());
            }
            prestat.close();

            ObjectDAO weaponDAO = new ObjectDAO(connection);
            for (BigInteger item : data_list) {
                weaponDAO.delete(item);
//                prestat = connection.prepareStatement(getQueryForDeleteFromParameters(item));
//                prestat.executeUpdate();
//                prestat.close();
//                prestat = connection.prepareStatement(getQueryForDeleteFromObjectReferences(item));
//                prestat.executeUpdate();
//                prestat.close();
            }
            logger.debug("Query = " + getQueryForPropertyTypeDefsForObjectType(id));
            prestat = connection.prepareStatement(getQueryForPropertyTypeDefsForObjectType(id));
            set = prestat.executeQuery();
            data_list = new LinkedList<BigInteger>();
            while (set.next()) {
                data_list.add(set.getBigDecimal(1).toBigInteger());
            }
            prestat.close();
            PropertyTypeDefsDAO propertyTypeDefsDAO = new PropertyTypeDefsDAO(connection);
            for (BigInteger item : data_list) {
                propertyTypeDefsDAO.delete(item);
            }
//            prestat = connection.prepareStatement(getQueryForDeleteFromObjects(id));
//            prestat.executeUpdate();
//            prestat.close();
            logger.debug("Query = " + getQueryForPropertyTypeDefsForObjectType(id));
            prestat = connection.prepareStatement(getQueryForDeleteFromObjectTypeProperties(id));
            prestat.executeUpdate();
            prestat.close();
            logger.debug("Query = " + getQueryForDelete(id));
            prestat = connection.prepareStatement(getQueryForDelete(id));
            prestat.executeUpdate();
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка удаления данных.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
    }
    
    
    
    private String getQueryForObjectTypeHeirsButNotDelete(BigInteger objectTypeId) {
        StringBuilder query = new StringBuilder();
        query.append("select object_type_id,name,description,parent_id,isAbstract,isDelete \n");
        query.append("from object_types obj_type\n");
        query.append("where obj_type.parent_id = ");
        query.append(objectTypeId);
        query.append("\n and isDelete=0");
        return query.toString();
    }

    public List<DBObjectType> getObjectTypeHeirsButNotDelete(BigInteger objectTypeId) throws DAOException {
        List<DBObjectType> data_list = new LinkedList<DBObjectType>();
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            logger.debug("Query = " + getQueryForObjectTypeHeirs(objectTypeId));
            prestat = connection.prepareStatement(getQueryForObjectTypeHeirsButNotDelete(objectTypeId));
            set = prestat.executeQuery();
            while (set.next()) {
                data_list.add(new DBObjectType(set.getBigDecimal(dbObjectTypesColumnName[0]).toBigInteger(),
                        set.getString(dbObjectTypesColumnName[1]),
                        set.getString(dbObjectTypesColumnName[2]),
                        set.getBigDecimal(dbObjectTypesColumnName[3]) != null
                        ? set.getBigDecimal(dbObjectTypesColumnName[3]).toBigInteger() : null,
                        set.getBoolean(dbObjectTypesColumnName[4]),
                        set.getBoolean(dbObjectTypesColumnName[5])));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_weapon_type", ex);
            throw new DAOException("Ошибка получения списка данных", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
        return data_list;

    }

}
